package com.mallify.common.utils;

import com.mallify.common.constants.Constants;
import com.mallify.common.exception.MallifyException;
import com.mallify.common.utils.vo.DateLimitUtilVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * Date工具类
 * +----------------------------------------------------------------------
 * | HANSON [ HANSON赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Licensed HANSON并不是自由软件，未经许可不能去掉HANSON相关版权
 * +----------------------------------------------------------------------
 * | Author: HANSON Team <hanson0622@126.com>
 * +----------------------------------------------------------------------
 */
public class DateUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(DateUtil.class);

    private DateUtil() {
        throw new IllegalStateException("Utility class");
    }

    public static void main(String[] args) {
        DateLimitUtilVo dateLimit = getDateLimit(Constants.SEARCH_DATE_LATELY_7);
        System.out.println(dateLimit.getStartTime());
        System.out.println(dateLimit.getEndTime());
    }

    /**
     * 计算时间范围
     *
     * @param date string 类型
     * @return dateLimitUtilVo
     * @author hanson.huang
     * @since 2025-02-8
     */
    public static DateLimitUtilVo getDateLimit(String date) {
        // 计算时间
        String startTime = null;
        String endTime = DateUtil.nowDateTime(Constants.DATE_FORMAT);
        String day = DateUtil.nowDateTime(Constants.DATE_FORMAT_START);
        String end = DateUtil.nowDateTime(Constants.DATE_FORMAT_END);

        if (!StringUtils.isBlank(date)) {
            switch (date) {
                case Constants.SEARCH_DATE_DAY:
                    startTime = day;
                    break;
                case Constants.SEARCH_DATE_YESTERDAY:
                    startTime = DateUtil.addDay(day, -1, Constants.DATE_FORMAT_START);
                    endTime = DateUtil.addDay(end, -1, Constants.DATE_FORMAT_END);
                    break;
                case Constants.SEARCH_DATE_LATELY_7:
                    startTime = DateUtil.addDay(day, -6, Constants.DATE_FORMAT_START);
                    break;
                case Constants.SEARCH_DATE_WEEK:
                    startTime = getWeekStartDayByJava8();
                    endTime = getWeekEndDay();
                    break;
                case Constants.SEARCH_DATE_PRE_WEEK:
                    startTime = getLastWeekStartDay();
                    endTime = getLastWeekEndDay();
                    break;
                case Constants.SEARCH_DATE_LATELY_30:
                    startTime = DateUtil.addDay(day, -30, Constants.DATE_FORMAT_START);
                    break;
                case Constants.SEARCH_DATE_MONTH:
                    startTime = DateUtil.nowDateTime(Constants.DATE_FORMAT_MONTH_START);
                    endTime = getMonthEndDayByJava8();
                    break;
                case Constants.SEARCH_DATE_PRE_MONTH:
                    startTime = getLastMonthStartDayByJava8();
                    endTime = getLastMonthEndDayByJava8();
                    break;
                case Constants.SEARCH_DATE_YEAR:
                    startTime = DateUtil.nowDateTime(Constants.DATE_FORMAT_YEAR_START);
                    endTime = DateUtil.nowDateTime(Constants.DATE_FORMAT_YEAR_END);
                    break;
                case Constants.SEARCH_DATE_PRE_YEAR:
                    startTime = getLastYearStartDayByJava8();
                    endTime = getLastYearEndDayByJava8();
                    break;
                default:
                    List<String> list = MallifyUtil.stringToArrayStr(date);
                    if (list.size() == 1) {
                        throw new MallifyException("选择时间参数格式错误，请在 " +
                                Constants.SEARCH_DATE_DAY + "|" +
                                Constants.SEARCH_DATE_YESTERDAY + "|" +
                                Constants.SEARCH_DATE_LATELY_7 + "|" +
                                Constants.SEARCH_DATE_LATELY_30 + "|" +
                                Constants.SEARCH_DATE_MONTH + "|" +
                                Constants.SEARCH_DATE_YEAR + "|自定义时间范围（格式：yyyy-MM-dd HH:mm:ss，两个时间范围用逗号分割）");
                    }
                    startTime = list.get(0);
                    endTime = list.get(1);
                    startTime = DateUtil.appointedDayStrToFormatStr(startTime, Constants.DATE_FORMAT_DATE, Constants.DATE_FORMAT_START);
                    endTime = DateUtil.appointedDayStrToFormatStr(endTime, Constants.DATE_FORMAT_DATE, Constants.DATE_FORMAT_END);
                    break;
            }
        }
        return new DateLimitUtilVo(startTime, endTime);
    }

    /**
     * 获取当前日期,指定格式
     * 描述:<描述函数实现的功能>.
     *
     * @return
     */
    public static Date nowDateTime() {
        return strToDate(nowDateTimeStr(), Constants.DATE_FORMAT);
    }

    /**
     * 获取当前日期,指定格式
     * 描述:<描述函数实现的功能>.
     *
     * @return
     */
    public static String nowDateTimeStr() {
        return nowDate(Constants.DATE_FORMAT);
    }

    /**
     * 获取当前日期,指定格式
     * 描述:<描述函数实现的功能>.
     *
     * @return
     */
    public static String nowDate(String DATE_FORMAT) {
        SimpleDateFormat dft = new SimpleDateFormat(DATE_FORMAT);
        return dft.format(new Date());
    }

    /**
     * 获取当前日期,指定格式
     * 描述:<描述函数实现的功能>.
     *
     * @return
     */
    public static String nowDateTime(String DATE_FORMAT) {
        SimpleDateFormat dft = new SimpleDateFormat(DATE_FORMAT);
        return dft.format(new Date());
    }

    /**
     * 获取当前时间戳（秒级）
     *
     * @return
     */
    public static Long getTime() {
        return (System.currentTimeMillis() / 1000L);
    }

    /**
     * 指定日期加上天数后的日期
     *
     * @param num     为增加的天数
     * @param newDate 创建时间
     * @return
     */
    public static final String addDay(String newDate, int num, String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        try {
            Date currdate = format.parse(newDate);
            Calendar ca = Calendar.getInstance();
            ca.setTime(currdate);
            ca.add(Calendar.DATE, num);
            return format.format(ca.getTime());
        } catch (Exception e) {
            LOGGER.error("转化时间出错,", e);
            return null;
        }
    }

    /**
     * 指定日期加上天数后的日期
     *
     * @param num     为增加的天数
     * @param newDate 创建时间
     * @return
     */
    public static final String addDay(Date newDate, int num, String pattern) {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        Calendar ca = Calendar.getInstance();
        ca.setTime(newDate);
        ca.add(Calendar.DATE, num);
        return format.format(ca.getTime());
    }

    /**
     * 获取当前日期,指定格式
     * 描述:<描述函数实现的功能>.
     *
     * @return
     */
    public static Integer getNowTime() {
        long t = (System.currentTimeMillis() / 1000L);
        return Integer.parseInt(String.valueOf(t));
    }

    /**
     * 获得本周第一天:yyyy-MM-dd HH:mm:ss
     */
    public static @Deprecated String getWeekStartDay() {
        Calendar c = Calendar.getInstance();
        // 这行代码的作用是调整 Calendar 实例的周数。由于参数是 0，实际上并没有改变当前周数，因此可以省略。
        c.add(Calendar.WEEK_OF_MONTH, 0);
        // 将 Calendar 实例的日期设置为当前周的周一。Calendar.DAY_OF_WEEK 表示星期几。2 表示周一（Calendar 中周日是 1，周一是 2，依此类推）。
        c.set(Calendar.DAY_OF_WEEK, 2);
        SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
        return startSdf.format(c.getTime());
    }

    /** 获得本周第一天:yyyy-MM-dd HH:mm:ss */
    /**
     * 改进：java8中使用LocalDate
     */
    public static String getWeekStartDayByJava8() {
        LocalDate today = LocalDate.now();
        LocalDate startOfWeek = today.with((DayOfWeek.MONDAY));// 获取当前周的周一
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00");
        return startOfWeek.format(formatter);
    }

    /**
     * 获得本周最后一天:yyyy-MM-dd HH:mm:ss
     */
    public static String getWeekEndDay() {
        return addDay(getWeekStartDayByJava8(), 7, Constants.DATE_FORMAT);
    }

    /**
     * 获得上周第一天:yyyy-MM-dd HH:mm:ss
     */
    public static String getLastWeekStartDay() {
        return addDay(getWeekStartDayByJava8(), -7, Constants.DATE_FORMAT);
    }

    /**
     * 获得上周最后一天:yyyy-MM-dd HH:mm:ss
     */
    public static String getLastWeekEndDay() {
        return addDay(getLastWeekStartDay(), 7, Constants.DATE_FORMAT);
    }

    /**
     * 获得本月最后一天:yyyy-MM-dd HH:mm:ss
     */
    public static @Deprecated String getMonthEndDay() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        SimpleDateFormat endSdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
        return endSdf.format(c.getTime());
    }

    /** 获得本月最后一天:yyyy-MM-dd HH:mm:ss */
    /**
     * 改进：java8中使用LocalDate
     */
    public static String getMonthEndDayByJava8() {
        LocalDate today = LocalDate.now();
        LocalDate lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59");
        return lastDayOfMonth.format(formatter);
    }

    /**
     * 获得上月第一天:yyyy-MM-dd HH:mm:ss
     */
    public static @Deprecated String getLastMonthStartDay() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, -1);
        c.set(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-01 00:00:00");
        return startSdf.format(c.getTime());
    }

    /**
     * 获得上月最后一天:yyyy-MM-dd HH:mm:ss
     */
    public static @Deprecated String getLastMonthEndDay() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MONTH, -1);
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        SimpleDateFormat endSdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
        return endSdf.format(c.getTime());
    }

    /** 获得上月第一天:yyyy-MM-dd HH:mm:ss */
    /**
     * 改进：java8中使用LocalDate
     */
    public static String getLastMonthStartDayByJava8() {
        LocalDate today = LocalDate.now();
        LocalDate firstDayOfLastMonth = today.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00");
        return firstDayOfLastMonth.format(formatter);
    }

    /** 获得上月最后一天:yyyy-MM-dd HH:mm:ss */
    /**
     * 改进：java8中使用LocalDate
     */
    public static String getLastMonthEndDayByJava8() {
        LocalDate today = LocalDate.now();
        LocalDate lastDayOfLastMonth = today.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59");
        return lastDayOfLastMonth.format(formatter);
    }

    /**
     * 获得上年第一天:yyyy-MM-dd HH:mm:ss
     */
    public static @Deprecated String getLastYearStartDay() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.YEAR, -1);
        SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-01-01 00:00:00");
        return startSdf.format(c.getTime());
    }

    /**
     * 获得上年最后一天:yyyy-MM-dd HH:mm:ss
     */
    public static @Deprecated String getLastYearEndDay() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.YEAR, -1);
        SimpleDateFormat endSdf = new SimpleDateFormat("yyyy-12-31 23:59:59");
        return endSdf.format(c.getTime());
    }

    /** 获得上年第一天:yyyy-MM-dd HH:mm:ss */
    /**
     * 改进：java8中使用LocalDate
     */
    public static String getLastYearStartDayByJava8() {
        LocalDate today = LocalDate.now();
        LocalDate firstDayOfLastYear = today.minusYears(1).withDayOfYear(1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 00:00:00");
        return firstDayOfLastYear.format(formatter);
    }

    /** 获得上年最后一天:yyyy-MM-dd HH:mm:ss */
    /**
     * 改进：java8中使用LocalDate
     */
    public static String getLastYearEndDayByJava8() {
        LocalDate today = LocalDate.now();
        LocalDate lastYear = today.minusYears(1);
        LocalDate lastDayOfLastYear = lastYear.withDayOfYear(lastYear.lengthOfYear());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd 23:59:59");
        return lastDayOfLastYear.format(formatter);
    }

    /**
     * 获取指定日期指定格式字符串
     *
     * @param dateStr
     * @param DATE_FORMAT
     * @return
     * @throws ParseException
     */
    public static String appointedDayStrToFormatStr(String dateStr, String STR_DATE_FORMAT, String DATE_FORMAT) {
        Date date = DateUtil.strToDate(dateStr, STR_DATE_FORMAT);
        return DateUtil.dateToStr(date, DATE_FORMAT);
    }

    /**
     * parse a String to Date in a specifies fromat.
     *
     * @param dateStr
     * @param DATE_FORMAT
     * @return
     * @throws ParseException
     */
    public static Date strToDate(String dateStr, String DATE_FORMAT) {
        SimpleDateFormat myFormat = new SimpleDateFormat(DATE_FORMAT);
        try {
            return myFormat.parse(dateStr);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * convert a date to string in a specifies fromat.
     *
     * @param date
     * @param DATE_FORMAT
     * @return
     */
    public static String dateToStr(Date date, String DATE_FORMAT) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat myFormat = new SimpleDateFormat(DATE_FORMAT);
        return myFormat.format(date);
    }

    /**
     * 获取某一时间段内的时间集合
     *
     * @param data string 类型
     * @return List<Date>
     * @author hanson.huang
     * @since 2025-02-8
     */
    public static List<String> getListDate(String data) {

        //获取30天的开始结束日期
        DateLimitUtilVo dateLimit = DateUtil.getDateLimit(data);

        //定义日期集合
        List<String> date = new ArrayList<>();

        //开始日期
        Date startDate = DateUtil.strToDate(dateLimit.getStartTime(), Constants.DATE_FORMAT);

        //结束日期
        Date endDate = DateUtil.strToDate(dateLimit.getEndTime(), Constants.DATE_FORMAT);

        while (endDate.after(startDate)) {
            date.add(DateUtil.dateToStr(startDate, Constants.DATE_FORMAT_DATE)); // 放入集合
            startDate = DateUtil.strToDate(DateUtil.addDay(startDate, 1, Constants.DATE_FORMAT), Constants.DATE_FORMAT); //循环一次 加一天
        }

        return date;
    }

    /**
     * compare two date String with a pattern
     *
     * @param date1
     * @param date2
     * @param pattern
     * @return
     */
    public static int compareDate(String date1, String date2, String pattern) {
        SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(pattern);
        try {
            Date dt1 = DATE_FORMAT.parse(date1);
            Date dt2 = DATE_FORMAT.parse(date2);
            if (dt1.getTime() > dt2.getTime()) {
                // date1 在 date2前
                return 1;
            } else if (dt1.getTime() < dt2.getTime()) {
                // date1在date2后
                return -1;
            } else {
                return 0;
            }
        } catch (ParseException e) {
            e.printStackTrace();
            return 0;
        }

    }
}